/**
  \file dawg_arr_template.c
  \author Francis Girard
  \date 30 september 2013

  Dawg array template.
*/


/*
 *  Copyright (C) 2013, Francis Girard
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */


#include <stdlib.h>
#include <string.h>
#include <assert.h>


//
// Struct Type Name Macros
//
#define _STRUCT_DAWG_ARR_TYPE_DEF(name) _Dawg_Array_##name
#define _STRUCT_DAWG_ARR_TYPE(name)     _STRUCT_DAWG_ARR_TYPE_DEF(name)
#define _STRUCT_DAWG_ARR_TYPE_NAME      _STRUCT_DAWG_ARR_TYPE(_NAME_)


#define STRUCT_DAWG_ARR_TYPE_DEF(name) Dawg_Array_##name
#define STRUCT_DAWG_ARR_TYPE(name)     STRUCT_DAWG_ARR_TYPE_DEF(name)
#define STRUCT_DAWG_ARR_TYPE_NAME      STRUCT_DAWG_ARR_TYPE(_NAME_)


typedef struct _STRUCT_DAWG_ARR_TYPE_NAME
{
  _TYPE_* pContent;
  unsigned int nSize;
  unsigned int nCapacity;
} STRUCT_DAWG_ARR_TYPE_NAME;



void DAWG_ARR_FUNC_NAME(realloc)(STRUCT_DAWG_ARR_TYPE_NAME* pArr, unsigned int nDesiredSize)
{
    if (pArr->nCapacity == 0)
      pArr->nCapacity = 1;

    for ( ; pArr->nCapacity < nDesiredSize; pArr->nCapacity *= 2) ;
    pArr->pContent = (_TYPE_*) realloc(pArr->pContent, sizeof(_TYPE_) * pArr->nCapacity);
}


H_DAWG_ARR_TYPE_NAME DAWG_ARR_FUNC_NAME(create)()
{
    STRUCT_DAWG_ARR_TYPE_NAME* pNewArr = (STRUCT_DAWG_ARR_TYPE_NAME*) malloc(sizeof(STRUCT_DAWG_ARR_TYPE_NAME));

    pNewArr->pContent = 0;
    pNewArr->nSize = 0;
    pNewArr->nCapacity = 0;

    return pNewArr;
}


H_DAWG_ARR_TYPE_NAME DAWG_ARR_FUNC_NAME(allocate)(unsigned int nInitialCapacity)
{
    STRUCT_DAWG_ARR_TYPE_NAME* pNewArr = (STRUCT_DAWG_ARR_TYPE_NAME*) DAWG_ARR_FUNC_NAME(create)();

    pNewArr->pContent = (_TYPE_*) malloc(sizeof(_TYPE_) * nInitialCapacity);
    pNewArr->nCapacity = nInitialCapacity;

    return pNewArr;
}


void DAWG_ARR_FUNC_NAME(destroy)(H_DAWG_ARR_TYPE_NAME hArr)
{
    STRUCT_DAWG_ARR_TYPE_NAME* pArr = (STRUCT_DAWG_ARR_TYPE_NAME*) hArr;
    assert(pArr);
    free(pArr->pContent);
    free(pArr);
}


_TYPE_ DAWG_ARR_FUNC_NAME(front)(H_DAWG_ARR_TYPE_NAME hArr)
{
    STRUCT_DAWG_ARR_TYPE_NAME* pArr = (STRUCT_DAWG_ARR_TYPE_NAME*) hArr;
    assert(pArr);
    assert(pArr->nSize > 0);
    return *(pArr->pContent);
}


_TYPE_ DAWG_ARR_FUNC_NAME(last)(H_DAWG_ARR_TYPE_NAME hArr)
{
    STRUCT_DAWG_ARR_TYPE_NAME* pArr = (STRUCT_DAWG_ARR_TYPE_NAME*) hArr;
    assert(pArr);
    assert(pArr->nSize > 0);
    return *(pArr->pContent + (pArr->nSize - 1));
}


_TYPE_ DAWG_ARR_FUNC_NAME(get_el)(H_DAWG_ARR_TYPE_NAME hArr, unsigned int nIdx)
{
    STRUCT_DAWG_ARR_TYPE_NAME* pArr = (STRUCT_DAWG_ARR_TYPE_NAME*) hArr;
    assert(pArr);
    assert(pArr->nSize > nIdx);
    return pArr->pContent[nIdx];
}


void DAWG_ARR_FUNC_NAME(set_el)(H_DAWG_ARR_TYPE_NAME hArr, unsigned int nIdx, _TYPE_ oEl)
{
    STRUCT_DAWG_ARR_TYPE_NAME* pArr = (STRUCT_DAWG_ARR_TYPE_NAME*) hArr;
    assert(pArr);
    assert(pArr->nSize > nIdx);
    pArr->pContent[nIdx] = oEl;
}


void DAWG_ARR_FUNC_NAME(push_back)(H_DAWG_ARR_TYPE_NAME hArr, _TYPE_ oNewEl)
{
    STRUCT_DAWG_ARR_TYPE_NAME* pArr = (STRUCT_DAWG_ARR_TYPE_NAME*) hArr;
    assert(pArr);
    if (pArr->nSize >= pArr->nCapacity)
    {
        DAWG_ARR_FUNC_NAME(realloc)(pArr, pArr->nSize+1);
    }
    pArr->pContent[pArr->nSize] = oNewEl;
    pArr->nSize++;
}


void DAWG_ARR_FUNC_NAME(append)(H_DAWG_ARR_TYPE_NAME hArr, H_DAWG_ARR_TYPE_NAME hArrToApp)
{
    STRUCT_DAWG_ARR_TYPE_NAME* pArr = (STRUCT_DAWG_ARR_TYPE_NAME*) hArr;
    STRUCT_DAWG_ARR_TYPE_NAME* pArrToApp = (STRUCT_DAWG_ARR_TYPE_NAME*) hArrToApp;
    assert(pArr);
    assert(pArrToApp);
    assert(pArr != pArrToApp); // because we use memcpy instead of memmove

    unsigned int nNewSize = pArr->nSize + pArrToApp->nSize;
    if (nNewSize > pArr->nCapacity)
    {
        DAWG_ARR_FUNC_NAME(realloc)(pArr, nNewSize);
    }
    memcpy(pArr->pContent + pArr->nSize,
           pArrToApp->pContent,
           sizeof(_TYPE_) * pArrToApp->nSize);
    pArr->nSize = nNewSize;
}


_TYPE_* DAWG_ARR_FUNC_NAME(begin)(H_DAWG_ARR_TYPE_NAME hArr)
{
    STRUCT_DAWG_ARR_TYPE_NAME* pArr = (STRUCT_DAWG_ARR_TYPE_NAME*) hArr;
    assert(pArr);
    return pArr->pContent;
}


_TYPE_* DAWG_ARR_FUNC_NAME(before_begin)(H_DAWG_ARR_TYPE_NAME hArr)
{
    _TYPE_* pReturn = DAWG_ARR_FUNC_NAME(begin)(hArr);
    pReturn--;
    return pReturn;
}


_TYPE_* DAWG_ARR_FUNC_NAME(end)(H_DAWG_ARR_TYPE_NAME hArr)
{
    STRUCT_DAWG_ARR_TYPE_NAME* pArr = (STRUCT_DAWG_ARR_TYPE_NAME*) hArr;
    assert(pArr);
    return pArr->pContent + pArr->nSize;
}


unsigned int DAWG_ARR_FUNC_NAME(size)(H_DAWG_ARR_TYPE_NAME hArr)
{
    STRUCT_DAWG_ARR_TYPE_NAME* pArr = (STRUCT_DAWG_ARR_TYPE_NAME*) hArr;
    assert(pArr);
    return pArr->nSize;
}


unsigned int DAWG_ARR_FUNC_NAME(capacity)(H_DAWG_ARR_TYPE_NAME hArr)
{
    STRUCT_DAWG_ARR_TYPE_NAME* pArr = (STRUCT_DAWG_ARR_TYPE_NAME*) hArr;
    assert(pArr);
    return pArr->nCapacity;
}


dawg_bool_t DAWG_ARR_FUNC_NAME(is_empty)(H_DAWG_ARR_TYPE_NAME hArr)
{
    STRUCT_DAWG_ARR_TYPE_NAME* pArr = (STRUCT_DAWG_ARR_TYPE_NAME*) hArr;
    assert(pArr);
    return pArr->nSize == 0;
}

dawg_bool_t DAWG_ARR_FUNC_NAME(substitute)(H_DAWG_ARR_TYPE_NAME hArr, _TYPE_ oElToRm, _TYPE_ oElReplaceant)
{
    dawg_bool_t bModified = dawg_false;
    STRUCT_DAWG_ARR_TYPE_NAME* pArr = (STRUCT_DAWG_ARR_TYPE_NAME*) hArr;
    assert(pArr);
    _TYPE_* pCur = pArr->pContent;
    _TYPE_* pEnd = pCur + pArr->nSize;
    for ( ; pCur != pEnd; pCur++)
    {
        if (*pCur == oElToRm)
        {
            *pCur = oElReplaceant;
            bModified = dawg_true;
        }
    }
    return bModified;
}

void DAWG_ARR_FUNC_NAME(sort)(H_DAWG_ARR_TYPE_NAME hArr,
                              int(*compar)(const void *, const void *))
{
    STRUCT_DAWG_ARR_TYPE_NAME* pArr = (STRUCT_DAWG_ARR_TYPE_NAME*) hArr;
    assert(pArr);

    // Standard C lib sort function defined in stdlib.h
    // It is named qsort because it had first been based
    // on the qsort algorithm.
    qsort(pArr->pContent, pArr->nSize, sizeof(_TYPE_), compar);
}
